/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.toolkit.dao;

import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.jdom.Attribute;
import org.jdom.Element;

import who.tmap.dao.TMapDAOException;
import who.tmap.toolkit.shape.LabelShape;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.toolkit.shape.MapShapes;
import who.tmap.toolkit.shape.PolygonShape;
import who.tmap.toolkit.shape.PolygonShapeDisputedBorder;
import who.tmap.toolkit.shape.annotation.LabelsListShape;
import who.tmap.toolkit.shape.impl.PolygonShapeDisputedBorderImpl;

/**
 * @author stl
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class PolygonShapeDAO extends BaseMapShapeDAO {
	
    private static Logger logger = Logger.getLogger(PolygonShapeDAO.class);  
    
    private Point2D distancePt =null;
    private boolean visible;    

	@SuppressWarnings("unchecked")
	public MapShape load( Element elt ) throws TMapDAOException {
	    PolygonShape pShape =null;
	    
        try {
            pShape = (PolygonShape)msf.getGraphic( MapShapes.POLYGON );
            
            Attribute visibleAttr =elt.getAttribute( "segmentsVisible" );
            if ( visibleAttr != null && !"".equals( visibleAttr ) ) {
            	pShape.setSegmentsVisible( visibleAttr.getBooleanValue() );
            } else {
            	pShape.setSegmentsVisible( true );
            }
               
            Iterator it =elt.getChildren().iterator();
            while( it.hasNext() ) {
                Element childElt =(Element)it.next();
                
                if ( "Annotations".equals( childElt.getName() ) ) {
                    pShape.setColor( getColorFromHexa( childElt.getAttribute( "rgb" ).getValue() ) );
                    pShape.setFillColor( getColorFromHexa( childElt.getAttribute( "fillColorRgb" ).getValue() ) );
                    
                    LabelShape labelShape =(LabelShape)msf.getGraphic( MapShapes.LABEL  );
                    labelShape.setDistancePt( new Point2D.Double( childElt.getAttribute( "x" ).getDoubleValue(),
							   									  -childElt.getAttribute( "y" ).getDoubleValue() ) );
                    labelShape.setVisible( childElt.getAttribute( "visible" ).getBooleanValue() );
                    labelShape.setMapShape( pShape );
                    
                    // Create a temporaty LabelsList
                    Attribute labelsList =childElt.getAttribute( "labelsList" );
                    if ( labelsList != null && !"".equals( labelsList.getValue() ) ) {
                    	LabelsListShape tmpLls =(LabelsListShape)msf.getGraphic( MapShapes.LABELS_LIST );
                    	tmpLls.setName( labelsList.getValue() );
                    	labelShape.setLabelsList( tmpLls);
                    } else {
                    	labelShape.setLabelsList( null );
                    }
                    
                    pShape.setLabelShape( labelShape );
                } else if ( "Name".equals( childElt.getName() ) ) {
                    pShape.setName( childElt.getText() );
                } else if ( "DisputedBorders".equals( childElt.getName() ) ) {
                	Iterator itDb =childElt.getChildren().iterator();
                	while( itDb.hasNext() ) {
                		Element dbElt =(Element)itDb.next();
                		
                		PolygonShapeDisputedBorder psdb =new PolygonShapeDisputedBorderImpl();
                		Line2D line2d =new Line2D.Float();
                		psdb.setLine( line2d );
                		line2d.setLine( dbElt.getAttribute( "x1" ).getFloatValue(), -dbElt.getAttribute( "y1" ).getFloatValue(),
                						dbElt.getAttribute( "x2" ).getFloatValue(), -dbElt.getAttribute( "y2" ).getFloatValue() );
                		psdb.setStroke( dbElt.getAttribute( "stroke" ).getIntValue() );
                		
                		pShape.getDisputedBorders().add( psdb );
                	}
                } else if ( "Coords".equals( childElt.getName() ) ) {
                	Iterator itCoords =childElt.getChildren().iterator();
                	while( itCoords.hasNext() ) {
                		Element coordsElt =(Element)itCoords.next();
                		
	                    Point2D pt =null;
	                    if ( !"Close".equals( coordsElt.getName() ) ) {
	                        pt =new Point2D.Double(
	                        				coordsElt.getAttribute( "x" ).getDoubleValue(),
	                                		-coordsElt.getAttribute( "y" ).getDoubleValue() );
	                    }
		
		                if ( "MoveTo".equals( coordsElt.getName() ) ) {
		                    pShape.moveTo( pt );
		                } else if ( "LineTo".equals( coordsElt.getName() ) ) {
		                    pShape.lineTo( pt );
		                } else if ( "Close".equals( coordsElt.getName() ) ) {
		                    pShape.close();
		                } else {
		                    throw new TMapDAOException( "invalid tag [" + coordsElt.getName() + "]" );
		                }
                	}
                }
            }
            
        } catch (Exception e) {
            throw new TMapDAOException( e );
        }
        
        //logger.debug( pShape.toString() );
        
        return pShape;
	}
	
	public Element save( MapShape mapShape ) throws TMapDAOException {
	    Element shapeElt =new Element( MapShapes.names[ MapShapes.POLYGON ] );//super.save( mapShape );
	    
        PolygonShape pShape =(PolygonShape)mapShape;
        
        // This attribute becomes optional
        // Only output when the polygon is invisible
        // as visible is the default
        if ( !pShape.isSegmentsVisible() ) {
        	shapeElt.setAttribute( "segmentsVisible", Boolean.toString( pShape.isSegmentsVisible() ) );
        }
        
        Element nameElt =new Element( "Name" );
        shapeElt.addContent( nameElt );       
        nameElt.setText( pShape.getName() );
        
        Element annotationsElt =new Element( "Annotations" );
        shapeElt.addContent( annotationsElt );
        annotationsElt.setAttribute( "rgb", Integer.toHexString( pShape.getColor().getRGB() ) );    
        annotationsElt.setAttribute( "fillColorRgb", pShape.getFillColor() != null ? Integer.toHexString( pShape.getFillColor().getRGB() ) : "" );            
        annotationsElt.setAttribute( "x", Double.toString( distancePt.getX() ) );
        annotationsElt.setAttribute( "y", Double.toString( -distancePt.getY() ) );
        annotationsElt.setAttribute( "visible", Boolean.toString( isVisible() ) );
        annotationsElt.setAttribute( "labelsList", pShape.getLabelShape().getLabelsList() != null 
        												? pShape.getLabelShape().getLabelsList().getName() 
        												: "" );
        
        Element coordsElt =new Element( "Coords" );
        shapeElt.addContent( coordsElt );
        
        String eltName;
		int type;
		float[] c =new float[6];
		PathIterator pit =pShape.getGeneralPath().getPathIterator(null);
		while( !pit.isDone() ) {
		       			    
			type = pit.currentSegment(c);  
			switch (type) {
				case PathIterator.SEG_MOVETO:
				    eltName ="MoveTo";
				    break;
				case PathIterator.SEG_LINETO:
				    eltName ="LineTo";
					break;
				case PathIterator.SEG_CLOSE:
				    eltName ="Close";
					break;
				default:
				    throw new TMapDAOException( "Unknown path iterator type [" + type + "]" );
			} 
			
			Element elt =new Element( eltName );
			if ( type != PathIterator.SEG_CLOSE ) {
			    elt.setAttribute( "x", Float.toString( c[0] ) );
			    elt.setAttribute( "y", Float.toString( -c[1] ) );
			}
			
			coordsElt.addContent( elt );
			
			pit.next();
		}	

		Element dbsElt =new Element( "DisputedBorders" );
		shapeElt.addContent( dbsElt );		
		
		for( PolygonShapeDisputedBorder db : pShape.getDisputedBorders() ) {
			Element dbElt =new Element( "DisputedBorder" );
			dbsElt.addContent( dbElt );
			
			dbElt.setAttribute( "x1", Float.toString( (float)db.getLine().getP1().getX() ) );
			dbElt.setAttribute( "y1", Float.toString( (float)-db.getLine().getP1().getY() ) );
			dbElt.setAttribute( "x2", Float.toString( (float)db.getLine().getP2().getX() ) );
			dbElt.setAttribute( "y2", Float.toString( (float)-db.getLine().getP2().getY() ) );
			dbElt.setAttribute( "stroke", Integer.toString( db.getStroke() ) );
		}
		
		return shapeElt;
	}

	public Point2D getDistancePt() {
		return distancePt;
	}

	public void setDistancePt(Point2D distPt) {
		this.distancePt = distPt;
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}
    
}
